#include "PointOfInterestNode.h"

#include <osg/Array>
#include <osg/Billboard>
#include <osg/BlendFunc>
#include <osg/Geometry>
#include <osg/ShapeDrawable>
#include <osg/StateSet>
#include <osg/Texture2D>
#include <osg/Vec4>
#include <osgDB/ReadFile>

#include <osg/LineWidth>


PointOfInterestNode::PointOfInterestNode(osg::Vec3 position, unsigned int category):osg::Group()
{
	// based on the category choose the right image based representation
	stylePointOfInterest(category);
	
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

    float width, height;
	osg::Vec3 widthVec;
	osg::Vec3 heightVec;
		
	// add the image to the geometry and init geometry based on the image dimensions
	if(m_image != NULL)
	{
		// add the image as texture
		osg::ref_ptr<osg::StateSet> stateset = geom->getOrCreateStateSet();
		osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
		texture->setImage(m_image);
		texture->setResizeNonPowerOfTwoHint(false);
		stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
		
		// tweak the texture to support transparent textures
		osg::ref_ptr<osg::BlendFunc> blend = new osg::BlendFunc();
		blend->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		stateset->setAttributeAndModes(blend);
		stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
	
		float aspectRatio = float(m_image->s())/float(m_image->t());
		// init fixed width for the billboard geometry
        if(category == 0 || category == 1)
        {
		    height = 50;
        }
        else
        {
            height = 250;
        }
		width = float(height*aspectRatio);	
		widthVec = osg::Vec3(width,0.f,0.f);
		heightVec = osg::Vec3(0.f,0.f,height);

        if(category == 0 || category == 1)
        {
		    position[2] = height;
        }
	
	}

	// init billboard geometry
	osg::Vec3 corner = osg::Vec3(-width/2.0,0.0,0.0);
	osg::Vec3 ll = corner;
	osg::Vec3 lr = corner + widthVec;
	osg::Vec3 ur = corner + widthVec+heightVec;
	osg::Vec3 ul = corner + heightVec;
	
	// geometry coords
	osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(4);
	(*coords)[0] = ll;
	(*coords)[1] = lr;
	(*coords)[2] = ur;
	(*coords)[3] = ul;

	geom->setVertexArray(coords);

	// colors
	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array();
	colors->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
	geom->setColorArray(colors);
	geom->setColorBinding(osg::Geometry::BIND_OVERALL);
	
	// normals
	osg::ref_ptr<osg::Vec3Array> norms = new osg::Vec3Array(1);
	(*norms)[0] = widthVec^heightVec;
	(*norms)[0].normalize();

	geom->setNormalArray(norms);
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

	// texture coords
	osg::ref_ptr<osg::Vec2Array> tcoords = new osg::Vec2Array(4);
	(*tcoords)[0].set(0.0f,0.0f);
	(*tcoords)[1].set(1.0f,0.0f);
	(*tcoords)[2].set(1.0f,1.0f);
	(*tcoords)[3].set(0.0f,1.0f);
	geom->setTexCoordArray(0,tcoords);

	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
	
	// initialize and add the billboard with the prior defined geometry
	osg::ref_ptr<osg::Billboard> bill = new osg::Billboard();
	bill->setMode(osg::Billboard::POINT_ROT_EYE);
	bill->addDrawable(geom, position);
	bill->setPosition(0,position);
	this->addChild(bill);

    // add simple line geometry
    if(category == 0 || category == 1)
    {
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        osg::ref_ptr<osg::Geometry> geomLine = new osg::Geometry;
        geode->addDrawable(geomLine.get());

        osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
        vertices->push_back(osg::Vec3(position.x(), position.y(), 0.0f));
        vertices->push_back(osg::Vec3(position.x(), position.y(), position.z())); // line to the sky
        geomLine->setVertexArray(vertices.get());

        osg::ref_ptr<osg::Vec4Array> colorLine = new osg::Vec4Array;
        colorLine->push_back(osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
        geomLine->setColorArray(colorLine.get());
        geomLine->setColorBinding(osg::Geometry::BIND_OVERALL);

        osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
        normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
        geomLine->setNormalArray(normals.get());
        geomLine->setNormalBinding(osg::Geometry::BIND_OVERALL);

        geomLine->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertices->size()));
        osg::StateSet* stateset = geomLine->getOrCreateStateSet();
        osg::LineWidth* linewidth = new osg::LineWidth;
        linewidth->setWidth(2.0f);
        stateset->setAttributeAndModes(linewidth, osg::StateAttribute::ON);
        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

        this->addChild(geode.get());
    }
}

PointOfInterestNode::~PointOfInterestNode()
{
	
	m_image = NULL;
}

void PointOfInterestNode::stylePointOfInterest(unsigned int category)
{
	switch(category)
	{
		case 0: // restaurant
			{
				m_image = osgDB::readImageFile("../osm/restaurant_symbol.png");
				break;
			}
		case 1: // marina
			{
				m_image = osgDB::readImageFile("../osm/marina_symbol.png");
				break;
			}
		case 2: // start marker
			{
				m_image = osgDB::readImageFile("../osm/map_marker3.png");
				break;
			}
        case 3: // end marker
            {
                m_image = osgDB::readImageFile("../osm/map_marker.png");
            }
		default:
			{
				m_image = osgDB::readImageFile("../osm/map_marker2.png");
				break;
			}
	}
	
}
